{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "92010cd5",
   "metadata": {},
   "source": [
    "# 2.3 优化提示词改善答疑机器人回答质量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0b18130",
   "metadata": {},
   "source": [
    "## 🚄 前言"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a33d28f-9014-414a-a7b5-b016e12d4bb0",
   "metadata": {},
   "source": [
    "上一节的答疑机器人已经可以回答关于公司规章制度的问题，但这仅仅是构建优秀用户体验的第一步。用户往往期待更个性化、更精准的交互。  \n",
    "本节将介绍提示词工程的技巧，教你如何通过优化提示词来改善或控制答疑机器人的输出，例如调整语气、规范格式，甚至赋予它处理文本总结、推断、转换等多种任务的能力。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37a39a58",
   "metadata": {},
   "source": [
    "## 🍁 课程目标\n",
    "\n",
    "学完本节课程后，你将能够：\n",
    "\n",
    "* 了解提示词框架和模板\n",
    "* 了解提示词技巧和最佳实践\n",
    "* 学习在工程中应用大模型处理多种不同类型的任务"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b0e80fa",
   "metadata": {},
   "source": [
    "## 1. 前文回顾\n",
    "\n",
    "上一节中通过RAG方法，大模型已经获取到了公司的私有知识。为了方便调用，将其封装成了几个函数，并保存在了 chatbot/rag.py 中。 现在你可以通过如下代码来快速调用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7aa6756d-47a4-4b11-8074-d992d6ce327b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:49:03.577636Z",
     "start_time": "2025-01-15T06:49:03.573248Z"
    }
   },
   "outputs": [],
   "source": [
    "from chatbot import rag\n",
    "import os\n",
    "from config.load_key import load_key"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f23f2c04-c229-4f5f-b2cd-50c8a45672e4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:49:09.717475Z",
     "start_time": "2025-01-15T06:49:09.713681Z"
    }
   },
   "outputs": [],
   "source": [
    "# 加载API密钥\n",
    "load_key()\n",
    "print(f'''你配置的 API Key 是：{os.environ[\"DASHSCOPE_API_KEY\"][:5]+\"*\"*5}''')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "91138451-fbc1-49ff-a268-2ece341b10bd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:49:11.770743Z",
     "start_time": "2025-01-15T06:49:11.611835Z"
    }
   },
   "outputs": [],
   "source": [
    "# 加载索引\n",
    "# 上小节已经建立了索引，因此这里可以直接加载索引。如果需要重建索引，可以增加一行代码：rag.indexing()\n",
    "index = rag.load_index()\n",
    "query_engine = rag.create_query_engine(index=index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d2d8d11-5a07-441c-9cd6-6ba10bf80603",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:49:16.961802Z",
     "start_time": "2025-01-15T06:49:16.959373Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义问答函数\n",
    "def ask_llm(question, query_engine):\n",
    "  streaming_response = query_engine.query(question)\n",
    "  streaming_response.print_response_stream()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1715f36",
   "metadata": {},
   "source": [
    "## 2. 优化提示词以改善大模型回答质量\n",
    "\n",
    "上一节中，你通过RAG方法获得了公司内部使用的管理工具。但你的同事希望答疑机器人不仅要给出工具名称，还需要附带工具链接。虽然可以让同事在提问时加上“给出下载地址”的说明，但是这种做法并不高效。因此你考虑改进程序：在收到用户问题后，补充一些对回答内容的要求。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b12a310a-660c-4cd3-9d23-8819bdefb8bb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:49:34.992776Z",
     "start_time": "2025-01-15T06:49:29.417135Z"
    }
   },
   "outputs": [],
   "source": [
    "question = \"我们公司项目管理应该用什么工具\"\n",
    "instruction = \"如果是工具咨询类问题，请务必给出下载地址链接。\"\n",
    "new_question = question + instruction\n",
    "ask_llm(new_question,query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "806fadd6-673a-4542-b3e2-fe36310b30ad",
   "metadata": {},
   "source": [
    "调整了提示的方式后，答疑机器人的回答更能符合同事的要求。所以提示词在很大程度上决定了大模型的回答质量，接下来你可以参考一些提示词框架构建提示词。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c006a5ea-5693-4805-9d2c-ccc0d2214939",
   "metadata": {},
   "source": [
    "## 3. 提示词框架\n",
    "\n",
    "### 3.1 基本要素\n",
    "\n",
    "当和大模型在交流时，可以将它想象是一个经过“社会化训练的”人，交流方式应当和人与人之间传递信息的方式一样。你的需求需要清晰明确，不能有歧义。你的提问方式（Prompt）越清晰明确，大模型越能抓住问题的关键点，回复就越符合你的预期。一般来说，提示词中需要明确以下几个要素：**任务目标、上下文、角色、受众、样例、输出格式**。这些要素构成了一个提示词框架，能帮助你构建一个完整、有效的提示词。\n",
    "\n",
    "|要素|含义|\n",
    "|----|----|\n",
    "|任务目标（Object）|明确要求大模型完成什么任务，让大模型专注具体目标|\n",
    "|上下文（Context）|任务的背景信息，比如操作流程、任务场景等，明确大模型理解讨论的范围|\n",
    "|角色（Role）|大模型扮演的角色，或者强调大模型应该使用的语气、写作风格等，明确大模型回应的预期情感|\n",
    "|受众（Audience）|明确大模型针对的特定受众，约束大模型的应答风格|\n",
    "|样例（Sample）|让大模型参考的具体案例，大模型会从中抽象出实现方案、需要注意的具体格式等信息|\n",
    "|输出格式（Output Format）|明确指定输出的格式、输出类型、枚举值的范围。通常也会明确指出不需要输出的内容和不期望的信息，可以结合样例来进一步明确输出的格式和输出方法|"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc35341a-3d7c-4881-81e3-935d42a1dcb2",
   "metadata": {},
   "source": [
    "当然，除了上面讲的提示词框架，许多问题分析的思维范式都可以用来帮助你描述清晰具体的需求。例如，SWOT分析法、5W2H分析法等。另外，你也可以考虑使用阿里云百炼提供的[提示词自动优化工具](https://bailian.console.aliyun.com/?tab=app#/component-manage/prompt/optimize)，来帮助你完善提示词。\n",
    "\n",
    "<a href=\"https://img.alicdn.com/imgextra/i3/O1CN014JCCqn22zX6xB4tt3_!!6000000007191-0-tps-2068-1052.jpg\" target=\"_blank\">\n",
    "<img src=\"https://img.alicdn.com/imgextra/i3/O1CN014JCCqn22zX6xB4tt3_!!6000000007191-0-tps-2068-1052.jpg\" width=\"700\"/>\n",
    "</a>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e1fa6d9",
   "metadata": {},
   "source": [
    "### 3.2 提示词模板\n",
    "\n",
    "在开发大模型应用时，直接让用户根据框架书写提示词并非最佳选择。你可以参考各种提示词框架中的要素，构建一个提示词模板。提示词模板可以预设部分信息，如大模型的角色、注意事项等，以此来约束大模型的行为。开发者只需在模板中配置输入参数，便能创建标准化的大模型的应用。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a84e29a3-a017-47c4-907e-2ff897333d1d",
   "metadata": {},
   "source": [
    "使用 LlamaIndex 中创建的 RAG应用中，有个默认的提示词模板，如下所示：\n",
    "\n",
    "- 默认的模板可以使用代码查看，你可以参考[LlamaIndex官网的代码。](https://docs.llamaindex.ai/en/stable/examples/prompts/prompts_rag/)LlamaIndex原始prompt模板为：\n",
    "\n",
    "```text\n",
    "Context information is below.\n",
    "---------------------\n",
    "{context_str}\n",
    "---------------------\n",
    "Given the context information and not prior knowledge, answer the query.\n",
    "Query: {query_str}\n",
    "Answer:\n",
    "```\n",
    "\n",
    "其中，`context_str`和`query_str`都表示变量。在进行向量检索和提问过程中，`context_str`将替换为从向量库中检索到的上下文信息，`query_str`则替换为用户的问题。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78ff8788-4d67-47b8-a4a2-3f3a85e6b0c5",
   "metadata": {},
   "source": [
    "由于原模板是通用模板，不适合用来约束答疑机器人的行为。你可以通过下列示例代码重新调整提示词模板，其中`prompt_template_string`表示新的提示词模板，你可以根据自己的场景自行修改。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05aea996-fdc8-4a35-922f-288313881fa3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T07:52:22.442975Z",
     "start_time": "2025-01-15T07:52:22.435217Z"
    }
   },
   "outputs": [],
   "source": [
    "# 构建提示词模板\n",
    "prompt_template_string = (\n",
    "    \"你是公司的客服小蜜，你需要简明扼要的回答用户的问题\"\n",
    "    \"【注意事项】：\\n\"\n",
    "    \"1. 依据上下文信息来回答用户问题。\\n\"\n",
    "    \"2. 你只需要回答用户的问题，不要输出其他信息\\n\"\n",
    "    \"以下是参考信息。\"\n",
    "    \"---------------------\\n\"\n",
    "    \"{context_str}\\n\"\n",
    "    \"---------------------\\n\"\n",
    "    \"问题：{query_str}\\n。\"\n",
    "    \"回答：\"\n",
    ")\n",
    "\n",
    "# 更新提示词模板\n",
    "rag.update_prompt_template(query_engine,prompt_template_string)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa99f324",
   "metadata": {},
   "source": [
    "## 4. 构建有效提示词的技巧\n",
    "\n",
    "在3.1中列举了一些提示词设计中的要素，接下来将从提示词要素出发，结合具体场景展开讲解提示词技巧。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1b3eb55-646d-41dd-b801-152d76205bbe",
   "metadata": {},
   "source": [
    "### 4.1 清晰表达需求，并使用分隔符\n",
    "\n",
    "明确的表达需求可以确保大模型生成的内容与任务高度相关。需求包括任务目标、背景及上下文信息，还可以使用分隔符将各种提示词要素隔开。\n",
    "\n",
    "分隔符可以使大模型抓住具体的目标，避免模糊的理解，也减少对不必要信息的处理。分隔符一般可以选择 “**【】**”、“**<< >>**”、“**###**”来标识关键要素，用“**===**”、“**---**”来分隔段落，或者使用xml标签如`<tag> </tag>`来对特定段落进行标识。当然，分隔符不止上述提到的几种，只需要起到明确阻隔的作用即可。需要注意的是，如果提示词中已大量使用某种符号（如【】），则应避免用该符号作为分隔符，以防混淆。\n",
    "\n",
    "在下面的示例中，将基于3.2中的提示词模板，以答疑机器人的身份帮你完成文档润色。\n",
    "\n",
    "- 你需要运行3.2中的代码，才能使新的提示词模板生效。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8918731d-49b6-4132-9ba5-2dce3eee360c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T07:52:32.192934Z",
     "start_time": "2025-01-15T07:52:24.619420Z"
    }
   },
   "outputs": [],
   "source": [
    "question = \"\"\"\n",
    "把下列【】括起来的文本进行扩写和润色，让文案生动且富有创造力，并且受到公司新员工的喜欢。\n",
    "【新员工训练营活动】\n",
    "\"\"\"\n",
    "ask_llm(question,query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62ae4c28-a2e6-4ad3-995b-7af2d78b19d1",
   "metadata": {},
   "source": [
    "由上述运行结果可以发现，提示词中明确了任务需求：对文本进行扩写和润色，任务主题为“**新员工训练营活动**”，受众为“**公司员工**”，并使用了“**【】**”分隔符分隔了文本。使用这样的提示词，让输出的文本不仅保持了原本的含义，还更加生动有趣。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7e4407d-3cff-4f00-a39b-b8ddfd7cce1d",
   "metadata": {},
   "source": [
    "### 4.2 限定角色和受众\n",
    "\n",
    "角色指大模型在特定场景下应扮演的身份，如专家、顾问或助手。受众是使用模型输出的目标用户群体，如普通消费者或学生。这有助于开发者定制内容的风格和深度。以下示例将展示不同的系统角色对输出文本风格和内容的影响，用户的问题为：qwen-vl是什么？\n",
    "\n",
    "- 以下仅演示提示词模板和输出的内容，你可以将提示词模板传入到`prompt_template_string`中，将用户问题传入到`question`中，再调用`ask_llm`函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79e5f128-8b02-40ca-b789-d577b6e38a3a",
   "metadata": {},
   "source": [
    "<table>\n",
    "  <thead>\n",
    "    <tr>\n",
    "      <th width = '80px'>角色</th>\n",
    "      <th width = '500px'>大模型算法工程师</th>\n",
    "      <th width = '500px'>小学老师</th>\n",
    "    </tr>\n",
    "  </thead>\n",
    "  <tbody valign = 'top'>\n",
    "    <tr>\n",
    "      <td>提示模板</td>\n",
    "      <td>\"你是资深的大模型算法工程师，请根据用户的问题进行解答\\n\"<br>\"---------------------\\n\"<br>\"{context_str}\\n\"<br>\"---------------------\\n\"<br>\"问题：{query_str}\\n。\"<br>\"回答：\"</td>\n",
    "      <td>\"你是一名小学老师，请根据用户的问题进行解答\\n\"<br>\"---------------------\\n\"<br>\"{context_str}\\n\"<br>\"---------------------\\n\"<br>\"问题：{query_str}\\n。\"<br>\"回答：\"</td>\n",
    "    </tr>\n",
    "    <tr>\n",
    "      <td>用户问题</td>\n",
    "      <td>Qwen-VL</td>\n",
    "      <td>Qwen-VL</td>\n",
    "    </tr>\n",
    "    <tr>\n",
    "      <td>输出回答</td>\n",
    "      <td>Qwen-VL是阿里巴巴云推出的一种多模态预训练模型，它结合了文本和图像处理能力，能够理解和生成与图像相关的文本描述。简单来说，Qwen-VL可以看作是一个能够“看图说话”的人工智能助手，它不仅能够理解图片的内容，还能根据图片内容生成相应的文字描述或回答相关问题。这种技术在多个领域都有广泛的应用前景，比如自动图像标注、视觉问答系统、基于内容的图像搜索等。对于新媒体运营而言，Qwen-VL这样的工具可以帮助提高内容创作效率，增强用户体验，为用户提供更加丰富多元的信息展示方式。</td>\n",
    "      <td>小朋友们，我们今天来认识一个新朋友，它的名字叫做Qwen-VL！<br>Qwen-VL就像是一个非常聪明的机器人，它拥有“眼睛”👀和“大脑”🧠。它能“看”图片、视频，还能理解它们的意思，就像我们一样！<br>比如，你给它看一张小猫玩毛线球的图片，它不仅能认出这是一只小猫🐱，还能告诉你它在玩毛线球🧶。 更厉害的是，你还可以问它：“小猫是什么颜色的？”，它就能告诉你小猫的颜色。<br>它还能理解视频里的内容，比如你给它看一段小朋友们踢足球⚽️的视频，它能告诉你谁在踢球，球踢到了哪里，甚至还能猜到接下来可能会发生什么！<br>Qwen-VL就像一个正在学习的小朋友，它还在不断地学习和进步，将来它会变得更聪明，能做更多的事情，帮助我们更好地了解这个世界！</td>\n",
    "    </tr>\n",
    "  </tbody>\n",
    "</table>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10f06bea-a34b-4e7a-b2b5-918af4c1ebdb",
   "metadata": {},
   "source": [
    "### 4.3 规定输出格式\n",
    "有时候，开发者在设计大模型应用时，需要采用结构化的数据作为下游系统的输入，才能完成整个应用的开发，但是一般大模型是输出连续的文本。不用担心，大模型有结构化输出的能力。你只需在提示词中指定输出的格式和要求，大模型有很大可能会输出结构化的内容。\n",
    "\n",
    "在下面的示例中，将基于3.2中的提示词模板，以答疑机器人的身份帮助公司开发的文档进行文档质量审查，并将结果以json的格式输出："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6692496-b6e4-4d75-aaa2-ef38b0c24f0c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:49:49.007218Z",
     "start_time": "2025-01-15T06:49:46.080617Z"
    }
   },
   "outputs": [],
   "source": [
    "question_task= \"\"\"\n",
    "【任务要求】\n",
    "你将看到一句话或一段话。你需要审查这段话中有没有错别字。如果出现了错别字，你要指出错误，并给出解释。\n",
    " “的” 和 “地” 混淆不算错别字，没有错误\n",
    "---\n",
    "【输出要求】\n",
    "请你只输出json格式，不要输出代码段\n",
    "其中，label只能取0或1，0代表有错误，1代表没有错误\n",
    "reason是错误的原因\n",
    "correct是修正后的文档内容\n",
    "---\n",
    "【用户输入】\n",
    "以下是用户输入，请审阅：\n",
    "\"\"\"\n",
    "question_doc = \"分隔符是特殊的符号，它们帮助大语言膜形 (LLM) 识别提示中哪些部分应当被视为一个完整的意思单元。\"\n",
    "\n",
    "question = question_task + question_doc\n",
    "ask_llm(question, query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebe59cd3-a241-4b28-902e-7ca35966e6a7",
   "metadata": {},
   "source": [
    "由上述示例的结果可知，在提示词`question_task`中注明了输出格式为json，也规定了输出的内容，大模型成功的输出了格式化的内容。这种稳定的格式化输出，使得在现有的系统中接入大模型这个操作变得具有可行性。\n",
    "\n",
    "在新闻网站、博客平台或企业内部的知识分享平台上，用户编辑或发布的文章可能会包含错别字、语法错误、甚至是敏感信息。但是传统的人工审核方式很容易出疏漏。这时候可以接入大模型来对内容做审查工作。如果文章被标记为存在严重语法错误或含有高风险敏感词汇，则将其修改的优先级设置为“高”。对于轻微问题的文章，则可以将其修改的优先级设置为“低”。这样会节省人力成本，提高系统的效率与准确性。\n",
    "\n",
    "当然了，类似于上述场景的应用非常多，开发者可以分析系统中流程的瓶颈或者关注数据密集型的任务，探索更多的大模型应用场景。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75f32b7a-9b47-40f1-82cb-e889a3b48048",
   "metadata": {},
   "source": [
    "### 4.4 提供少样本示例\n",
    "\n",
    "在4.3的例子中，提示词规定了输出的格式，大模型成功生成了格式化的内容。然而，如果希望大模型输出的内容不仅格式正确，而且风格和结构也保持一致，可以提供几个样例作为参考。这相当于给大模型提供了一本“参考书”。下面的代码示例中，先观察下没有样例时的大模型的输出吧！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "afcca16d368baf38",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T07:20:42.883097Z",
     "start_time": "2025-01-15T07:20:18.423060Z"
    }
   },
   "outputs": [],
   "source": [
    "question_task = \"\"\"\n",
    "【任务要求】\n",
    "请你根据用户的主题，创作内容。\n",
    "---\n",
    "【输出要求】\n",
    "最终输出需要以Markdown格式呈现，请注意，在你的回答中包含所有必要的Markdown元素，如标题、列表、链接、图片引用、加粗等，以便于阅读、后续编辑和保存。\n",
    "---\n",
    "【用户输入】\n",
    "以下是用户的要求创作的主题：\n",
    "\"\"\"\n",
    "question_doc = \"手工钥匙扣制作教程\"\n",
    "\n",
    "question = question_task + question_doc\n",
    "ask_llm(question, query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30f61d316e005c4f",
   "metadata": {},
   "source": [
    "上述示例大模型成功了输出了手工钥匙扣制作教程，但是内容不够简洁，如果只想大模型输出特定风格和结构的内容，如只输出主题、材料清单、步骤等内容，可以为大模型添加几个样例，让它去“模仿”！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c1e0f67f703e7ba",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:50:39.297041Z",
     "start_time": "2025-01-15T06:50:24.071562Z"
    }
   },
   "outputs": [],
   "source": [
    "question_task= \"\"\"\n",
    "【任务要求】\n",
    "请根据用户的主题，结合下面【样例】给的例子，理解和使用一致的风格和结构继续创作内容，不要输出多余的内容。\n",
    "---\n",
    "【输出要求】\n",
    "最终输出需要以Markdown格式呈现，请注意，在你的回答中包含所有必要的Markdown元素，如标题、列表、链接、图片引用、加粗等，以便于阅读、后续编辑和保存。\n",
    "---\n",
    "【样例】\n",
    "### 示例1: 制作简易书签\n",
    "# 简易书签制作教程\n",
    "\n",
    "## 材料清单\n",
    "- 彩色卡纸\n",
    "- 剪刀\n",
    "- 装饰贴纸\n",
    "- 铅笔\n",
    "\n",
    "## 步骤\n",
    "1. 选择一张彩色卡纸。\n",
    "2. 用铅笔在卡纸上画出一个长方形，尺寸约为2英寸 x 6英寸。\n",
    "3. 沿着铅笔线剪下长方形。\n",
    "4. 使用装饰贴纸对书签进行个性化装饰。\n",
    "5. 完成！现在你有了一个独一无二的书签。\n",
    "\n",
    "## 结束语\n",
    "希望这个教程能帮助你制作出满意的书签！\n",
    "\n",
    "---\n",
    "【用户输入】\n",
    "以下是用户的要求创作的主题：\n",
    "\"\"\"\n",
    "question_doc = \"制作手工贺卡\"\n",
    "\n",
    "question = question_task + question_doc\n",
    "ask_llm(question, query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e95447ee9772539d",
   "metadata": {},
   "source": [
    "由上述示例结果可知，大模型完全按照了样例输出了相同结构和风格的内容。在提示词中规定输出格式的同时，建议提供几个样例供大模型参考，这样可以使得大模型的输出更加稳定和一致。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53569b47-1619-4527-a9c8-b53f5e5bdf8d",
   "metadata": {},
   "source": [
    "### 4.5 给模型“思考”的时间\n",
    "\n",
    "对于一些复杂的任务来说，使用上面提到的提示词也许还不能帮助大模型完成任务。但是你可以通过让大模型一步步“思考”，引导大模型输出任务的中间步骤，允许大模型在进行推理之前，得到更多的依据，从而提升在复杂任务的表现能力。思维链（COT）方法是让模型进行思考的一种方法。它通过让模型处理中间步骤，逐步将复杂问题分解为子问题，最终推导出正确答案。\n",
    "\n",
    "假设有这样的场景，让大模型计算下面这道数学题，在此先提示一下，这道题的正确答案为10500元。先使用简单的提示词："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3569f469-c601-406a-a26d-fb0a74157c68",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:50:42.416991Z",
     "start_time": "2025-01-15T06:50:41.378053Z"
    }
   },
   "outputs": [],
   "source": [
    "question = \"\"\"\n",
    "【背景信息】\n",
    "某教育培训机构（以下简称“公司”）在2023年度发生了以下主要支出：\n",
    "为了给不同城市的学校学生上课，公司的老师全年共出差了5次，每次出差时间为一周，具体费用如下：\n",
    "   - 交通费及住宿费：平均1600元/次\n",
    "   - 教学用具采购费用：公司在年初一次性购买了一批教学用具，总价为10000元，预计可以使用4年。\n",
    "   \n",
    "【问题描述】\n",
    "请根据上述背景信息，完成以下任务：\n",
    "计算全年因教师出差而产生的差旅总费用，包括摊销的教学用具。\n",
    "\n",
    "【输出要求】\n",
    "直接给出总差旅费用，不要其他信息\"\"\"\n",
    "\n",
    "ask_llm(question, query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "edf9078a-f716-4537-b003-a90d70f988b5",
   "metadata": {},
   "source": [
    "由上面的实验结果来看，大模型计算结果不正确。下面将使用COT方法，让大模型逐步进行思考。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "92cb1715-305c-43ee-bd5e-274d2556ad56",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:50:55.556383Z",
     "start_time": "2025-01-15T06:50:43.720893Z"
    }
   },
   "outputs": [],
   "source": [
    "question = \"\"\"某教育培训机构（以下简称“公司”）在2023年度发生了以下主要支出：\n",
    "为了给不同城市的学校学生上课，公司的老师全年共出差了5次，每次出差时间为一周，具体费用如下：\n",
    "   - 交通费及住宿费：平均1600元/次\n",
    "   - 教学用具采购费用：公司在年初一次性购买了一批教学用具，总价为10000元，预计可以使用4年。\n",
    "   \n",
    "### 问题描述\n",
    "请根据上述背景信息，完成以下任务：\n",
    "计算全年因教师出差而产生的差旅总费用，包括摊销的教学用具。\n",
    "\n",
    "### 输出要求\n",
    "请你一步步推导，计算总差旅费用\"\"\"\n",
    "\n",
    "ask_llm(question, query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0ec9cdf-d6e1-469f-9e4c-f91fdf7f1c3e",
   "metadata": {},
   "source": [
    "经过优化后的提示词，大模型能够准确计算出结果。因此在开发大模型应用时，可以在提示词中添加思维链的方法，可以确保一些推理任务能正确执行。  \n",
    "\n",
    "使大模型进行 “思考”的方法还有很多种，比如：思维树（ToT)、思维图（GOT） 等。但是就目前大模型的发展来说，仅靠引导大模型“思考”还是无法完成更复杂的工作。大模型也逐渐从COT的提示方法向多智能体（Agent）方向进行发展。你可以在<2.6 用插件扩展答疑机器人的能力边界>阅读详细内容。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6214d05f-8154-44f7-943b-7f04196a3275",
   "metadata": {},
   "source": [
    "## 5. 使用大模型进行意图识别\n",
    "\n",
    "经过学习了提示词技术，同事们了解了答疑机器人不仅可以用来查资料，还可以用来帮助他们审查文档、翻译文档。尽管大多数情况下，你的答疑机器人是可以帮助发现问题的，但答疑机器人仍存在一些不足。如下示例所示：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b21013ec-b0e4-4428-9bb1-e2f309df563a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:51:02.890690Z",
     "start_time": "2025-01-15T06:51:00.165152Z"
    }
   },
   "outputs": [],
   "source": [
    "rag.ask('请帮我审查下这句话：技术内容工程师需要设计和开发⾼质量的教育教材和课程吗？', query_engine=query_engine)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25dd1116-048c-4599-ba9d-98750978504a",
   "metadata": {},
   "source": [
    "由上面的实验结果可知，答疑机器人直接对这段话进行了回答，并没有理解你需要它对这句话进行审查的意图。下面来查看下，答疑机器人在回答之前从知识库中召回了哪些内容，下列仅展示召回的部分内容：\n",
    "\n",
    "- 你可以在<2.4 自动化评测答疑机器人的表现>中，了解如何查看从知识库召回的片段。\n",
    "\n",
    "```json\n",
    "片段: 内容开发工程师\n",
    "......\n",
    "1. 内容研究与分析\n",
    "对最新的教育技术趋势、学习理论和市场需求进行深入研究。这包括分析竞争对手的产品，评估现有教育资源的有效性，并探索如何将新兴技术（如人工智能、虚拟现实等）整合进我们的教育内容中。通过持续的市场调研，我能够确保我们的内容在技术上始终处于前沿，并能够满足教育者和学习者的真实需求。\n",
    "\n",
    "2. 教材和课程开发\n",
    "根据研究和市场反馈，我将设计和开发高质量的教育教材和课程。这包括撰写教学大纲、制作课件、设计评估工具等。我的职责还包括确保内容符合教育标准和学习目标，以提供全面的学习体验。同时，我会考虑不同学习者的需求，确保内容能够适应各种学习风格和水平。\n",
    "......\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cfe0c766-2ee9-446f-95ee-c9bb829bedce",
   "metadata": {},
   "source": [
    "从知识库召回的片段可知，大部分内容都涉及技术内容工程师的工作职责，可以认为答疑机器人被知识库中的上下文干扰了，导致其回答的内容偏离了文档审查的主题。\n",
    "\n",
    "既然上下文信息影响了大模型的回答，那么就不必每次提问都使用RAG方法。你可以借助大模型先进行意图识别：对用户的问题进行分类，如果是文档审查、内容翻译等任务，会直接输入给大模型来生成答案，如果是内部知识查询问题，才经过RAG 链路来生成答案。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5df6389a-cfa2-450e-b7fe-72e24dd79838",
   "metadata": {},
   "source": [
    "<img src=\"https://img.alicdn.com/imgextra/i1/O1CN0126zKe71PAuJjWfQ3N_!!6000000001801-0-tps-2254-1080.jpg\" width=\"800\">"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9fe0489-872c-466b-855a-3768a5127f9e",
   "metadata": {},
   "source": [
    "让大模型进行意图识别也有以下两种方法： \n",
    "\n",
    "- 使用提示词：通过设计特定的提示词，引导大模型生成符合预期的回答。这种方法不需要修改模型本身的参数，而是依靠构造的输入来激发模型内部已有的知识。\n",
    "- 对模型进行微调：基于一个经过预训练的基础模型，使用特定的标注数据进一步训练该模型，使其更好的对意图进行分类。微调涉及调整模型的部分或全部参数。\n",
    "\n",
    "在本节中，将借助书写有效的提示词帮助大模型进行意图识别，通过微调的方法你可以在<2.7 通过微调提升模型的准确度与效率>小节进行学习。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe46f635-ac13-488d-9ab7-89b49ae8878d",
   "metadata": {},
   "source": [
    "### 5.1 意图识别\n",
    "\n",
    "接下来，将构建提示词使大模型对问题分类。由于经过意图识别后要取得格式化的内容，才能进行文档审查或者使用RAG应用，所以为了能将用户的问题准确分类，将考虑以下提示词技巧：\n",
    "- 明确输出格式：指定输出格式，使分类结果规范且易于解析。\n",
    "- Few-shot 示例：提供示例，帮助大模型理解每个类别的特征和分类规则。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63ff599e-a7fa-41d8-b734-d949e9f93900",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:51:10.939753Z",
     "start_time": "2025-01-15T06:51:09.207243Z"
    }
   },
   "outputs": [],
   "source": [
    "from chatbot import llm\n",
    "  \n",
    "# 构建提示词\n",
    "prompt = '''\n",
    "【角色背景】\n",
    "你是一个问题分类路由器，负责判断用户问题的类型，并将其归入下列三类之一：\n",
    "1. 公司内部文档查询\n",
    "2. 内容翻译\n",
    "3. 文档审查\n",
    "\n",
    "【任务要求】\n",
    "你的任务是根据用户的输入内容，判断其意图并仅选择一个最贴切的分类。请仅输出分类名称，不需要多余的解释。判断依据如下：\n",
    "\n",
    "- 如果问题涉及公司政策、流程、内部工具或职位描述与职责等内容，选择“公司内部文档查询”。\n",
    "- 如果问题涉及任意一门非中文的语言，且输入中出现任何外语或“翻译”等字眼，选择“内容翻译”。\n",
    "- 如果问题涉及检查或总结外部文档或链接内容，选择“文档审查”。\n",
    "- 用户的前后输入与问题分类并没有任何关系，请单独为每次对话考虑分类类别。\n",
    "\n",
    "【Few-shot 示例】\n",
    "示例1：用户输入：“我们公司内部有哪些常用的项目管理工具？”\n",
    "分类：公司内部文档查询\n",
    "\n",
    "示例2：用户输入：“请翻译下列句子：How can we finish the assignment on time?”\n",
    "分类：内容翻译\n",
    "\n",
    "示例3：用户输入：“请审查下这个链接下的文档：https://help.aliyun.com/zh/model-studio/user-guide/long-context-qwen-long”\n",
    "分类：文档审查\n",
    "\n",
    "示例4：用户输入：“请审查以下内容：技术内容工程师需要设计和开发⾼质量的教育教材和课程吗？”\n",
    "分类：文档审查\n",
    "\n",
    "示例5：用户输入：“技术内容工程师核心职责是什么？”\n",
    "分类：公司内部文档查询\n",
    "\n",
    "【用户输入】\n",
    "以下是用户的输入，请判断分类：\n",
    "'''\n",
    "\n",
    "# 获取问题的类型\n",
    "def get_question_type(question):\n",
    "    return llm.invoke(prompt + question)\n",
    "\n",
    "print(get_question_type('https://www.promptingguide.ai/zh/techniques/fewshot'),'\\n')\n",
    "print(get_question_type('That is a big one I dont know why'),'\\n')\n",
    "print(get_question_type('作为技术内容工程师有什么需要注意的吗？'),'\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f74506a-504d-47a2-bb9d-e17198294445",
   "metadata": {},
   "source": [
    "通过明确的输出格式和 few-shot 示例，答疑机器人可以更准确地识别问题类型并输出符合预期的格式。这种优化让分类任务更加标准化，为接下来添加意图识别到答疑机器人中打下了基础。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb001699-4451-4e1f-808d-1b38a80c9431",
   "metadata": {},
   "source": [
    "### 5.2 将意图识别应用到答疑机器人中\n",
    "\n",
    "对用户的问题进行意图识别后，你就可以让答疑机器人先识别问题的类型，再使用不同的提示词和工作流程来回答问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c5d8de14-53ee-4d5f-8f5a-0dfd9bf4e0ba",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:51:13.272321Z",
     "start_time": "2025-01-15T06:51:13.111875Z"
    }
   },
   "outputs": [],
   "source": [
    "def ask_llm_route(question):\n",
    "    question_type = get_question_type(question)\n",
    "    print(f'问题：{question}\\n类型：{question_type}')\n",
    "  \n",
    "    reviewer_prompt = \"\"\"\n",
    "    【角色背景】\n",
    "    你是文档纠错专家，负责找出文档中或网页内容的明显错误\n",
    "    【任务要求】\n",
    "    - 你需要言简意赅的回复。\n",
    "    - 如果没有明显问题，请直接回复没有问题\\n\n",
    "    【输入如下】\\n\"\"\"\n",
    "  \n",
    "    translator_prompt = \"\"\"\n",
    "   【任务要求】\n",
    "    你是一名翻译专家，你要识别不同语言的文本，并翻译为中文。\n",
    "    【输入如下】\\n\"\"\"\n",
    "\n",
    "    if question_type == '文档审查':\n",
    "        return llm.invoke(reviewer_prompt + question)\n",
    "    elif question_type == '公司内部文档查询':\n",
    "        return rag.ask(question, query_engine=query_engine)\n",
    "    elif question_type == '内容翻译':\n",
    "        return llm.invoke(translator_prompt + question)\n",
    "    else:\n",
    "        return \"未能识别问题类型，请重新输入。\"\n",
    "\n",
    "query_engine =rag.create_query_engine(index=rag.load_index())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d5d6ec83-8a99-45a5-a305-5088adc89be0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-15T06:51:22.925058Z",
     "start_time": "2025-01-15T06:51:14.191174Z"
    }
   },
   "outputs": [],
   "source": [
    "# 问题1\n",
    "print(ask_llm_route('https://www.promptingguide.ai/zh/techniques/fewshot'),'\\n')\n",
    "\n",
    "# 问题2\n",
    "print(ask_llm_route('请帮我检查下这段文档：技术内容工程师有需要进行内容优化与更新与跨部门合作吗？'),'\\n')\n",
    "\n",
    "# 问题3\n",
    "print(ask_llm_route('技术内容工程师有需要进行内容优化与更新与跨部门合作吗？'),'\\n')\n",
    "\n",
    "# 问题4:\n",
    "print(ask_llm_route('A true master always carries the heart of a student.'),'\\n')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6a95edd-ca52-434f-b6b5-6b0537fdfec6",
   "metadata": {},
   "source": [
    "从上述实验中可以看出，优化后的答疑机器人，并不是每次提问都会经过RAG链路，这不仅节省了资源，还避免了知识库的信息，干扰了大模型的推理，从而导致回答质量不好。\n",
    "- 节省资源：对于检查文档错误的问题，大模型其实可以直接回复，并不需要检索参考资料，之前的实现存在资源浪费。\n",
    "- 避免误解：之前的实现每次会检索参考资料，这些被召回的相关文本段可能会干扰大模型理解问题，导致答非所问。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7c107a1",
   "metadata": {},
   "source": [
    "## 6. 推理大模型\n",
    "\n",
    "前面所讲的提示词技巧和提示词框架可以广泛适用于通用大模型（如Qwen2.5-max、GPT-4、DeepSeek-V3），这类模型面向通用对话、知识问答、文本生成等广泛的场景。除了通用大模型，目前还有一类专门为“推理”设计的大模型——`推理大模型`。\n",
    "\n",
    "### 6.1 什么是推理大模型?\n",
    "\n",
    "你可能已经通过2.1节的扩展阅读了解了阿里云的推理大模型[QwQ](https://help.aliyun.com/zh/model-studio/user-guide/qwq) 。为了方便本节后续调用，改写了2.1节中提供的代码，你可以尝试运行以下代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "500b6e30",
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "import os\n",
    "\n",
    "def reasoning_model_response(user_prompt, system_prompt=\"你是一个编程助手。\", model=\"qwq-32b\"):\n",
    "    \"\"\"\n",
    "    prompt: 用户输入的提示词\n",
    "    model: 此处以 qwq-32b 为例，可按需更换推理模型名称，如：deepseek-r1\n",
    "    \"\"\"\n",
    "    # 初始化客户端\n",
    "    client = OpenAI(\n",
    "        api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "        base_url=\"https://dashscope.aliyuncs.com/compatible-mode/v1\"\n",
    "    )\n",
    "\n",
    "    # 初始化状态变量\n",
    "    is_answering = False\n",
    "\n",
    "    # 发起流式请求\n",
    "    completion = client.chat.completions.create(\n",
    "        model=model,\n",
    "        # messages=[{\"role\": \"user\", \"content\": prompt}],\n",
    "        messages=[\n",
    "            {\"role\": \"system\", \"content\": system_prompt},\n",
    "            {\"role\": \"user\", \"content\": user_prompt}\n",
    "        ],\n",
    "        stream=True,\n",
    "    )\n",
    "\n",
    "    # 打印思考过程标题\n",
    "    print(\"\\n\" + \"=\" * 20 + \"思考过程\" + \"=\" * 20 + \"\\n\")\n",
    "\n",
    "    # 处理流式响应\n",
    "    for chunk in completion:\n",
    "        if chunk.choices:\n",
    "            delta = chunk.choices[0].delta\n",
    "            if hasattr(delta, 'reasoning_content') and delta.reasoning_content is not None:\n",
    "                # 处理思考过程内容\n",
    "                print(delta.reasoning_content, end='', flush=True)\n",
    "            else:\n",
    "                # 切换到答案输出模式\n",
    "                if delta.content != \"\" and not is_answering:\n",
    "                    print(\"\\n\" + \"=\" * 20 + \"完整回复\" + \"=\" * 20 + \"\\n\")\n",
    "                    is_answering = True\n",
    "                # 处理答案内容\n",
    "                if delta.content:\n",
    "                    print(delta.content, end='', flush=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9e65df7d",
   "metadata": {},
   "outputs": [],
   "source": [
    "reasoning_model_response(user_prompt=\"你是谁？\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3fea9f93",
   "metadata": {},
   "source": [
    "\n",
    "通过例子可以看到，推理模型相较于通用大模型多出了“`思考过程`”，就像解数学题时有人会先在草稿纸上一步步推导，而不是直接报答案，减少模型出现“拍脑袋”的错误，同时在分步思考过程中，如果某一步骤发现矛盾，还可以回头检查并重新调整思路，展示推理步骤还可以方便人们理解，顺着模型的思考路线验证逻辑。<br>\n",
    "相较于通用大模型，推理大模型通常在解决复杂问题时更可靠，比如在数学解题、代码编写、法律案件分析等需要严谨推理的场景。并不是说推理模型一定更好，两种模型都有各自的应用场景，下表从一些典型维度对这两类模型进行了对比：<br>\n",
    "\n",
    "| 维度            | 推理模型  | 通用模型  |\n",
    "|-------------------|------------------|------------|\n",
    "| 设计目标     | 专注于**逻辑推理、多步问题求解、数学计算**等需要深度分析的任务 | 面向**通用对话、知识问答、文本生成**等广泛场景 |\n",
    "| 训练数据侧重  | 大量**数学题解、代码逻辑、科学推理**数据集增强推理能力 | 覆盖**百科、文学、对话**等多领域海量数据 |\n",
    "| 典型输出特征 | 输出包含**完整推导**步骤，注重逻辑链条的完整性 | 输出**简洁直接**，侧重结果的自然语言表达 |\n",
    "| 响应速度 | 复杂推理任务**响应较慢**（需多步计算） | 常规任务**响应更快**（单步生成为主） |\n",
    "\n",
    "推理模型还是通用模型？如何选择？以下是一些推荐：\n",
    "- **明确的通用任务**：对于明确定义的问题，**通用模型**一般能够很好地处理。\n",
    "- **复杂任务**：对于非常复杂的任务，且需要给出相对**更精确和可靠**的答案，推荐使用**推理模型**。这些任务可能有：\n",
    "    - 模糊的任务：任务相关信息很少，你无法提供模型相对明确的指引。\n",
    "    - 大海捞针：传递大量非结构化数据，提取最相关的信息或寻找关联/差别。\n",
    "    - 调试和改进代码：需要审查并进一步调试、改进大量代码。\n",
    "- **速度和成本**：一般来说推理模型的推理时间较长，如果你对于时间和成本敏感，且任务复杂度不高，**通用模型**可能是更好的选择。<br>\n",
    "\n",
    "当然你还可以在你的应用中结合使用两种模型：使用推理模型完成Agent的规划和决策，使用通用模型完成任务执行。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "580c0b84",
   "metadata": {},
   "source": [
    "### 6.2 适用于推理大模型的提示词技巧\n",
    "\n",
    "推理模型在面对相对模糊的任务也能给出详尽且格式良好的响应。你依然可以通过**提示词技巧**保证推理大模型的推理质量的下限：<br>\n",
    "#### 技巧一：保持任务提示简洁清晰，提供足够的背景信息<br>\n",
    "本节4.1中介绍的**清晰表达需求**同样适用于推理模型，虽然推理模型能力很强，但却不能“看穿人的想法”，你需要保持提示**简洁、清晰**，从而让推理大模型专注于核心任务。<br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe5cc8ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "bad_prompt=\"\"\"\n",
    "def example(a):\n",
    "  b = []\n",
    "  for i in range(len(a)):\n",
    "    b.append(a[i]*2)\n",
    "  return sum(b)\n",
    "\"\"\"\n",
    "\n",
    "reasoning_model_response(user_prompt=bad_prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "61e6f145",
   "metadata": {},
   "source": [
    "通过如上示例，可以看到就算你只给推理大模型一段代码，它还是能够通过一系列的推理给出很丰富的答案，但返回的推理中可能包含了很多你不关注的信息，你可以尝试明确**任务目标**，从而获得更有针对性的建议："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10c90bd3",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_A=\"\"\"\n",
    "如下 python 代码有什么问题？怎么优化？\n",
    "def example(a):\n",
    "  b = []\n",
    "  for i in range(len(a)):\n",
    "    b.append(a[i]*2)\n",
    "  return sum(b)\n",
    "\"\"\"\n",
    "\n",
    "reasoning_model_response(user_prompt=prompt_A)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5500ab0",
   "metadata": {},
   "source": [
    "同样地，你还可以在结合本节**4.2 限定角色和受众**、**4.3规定输出格式**等技巧进一步限定范围，确保结果符合你的预期。<br>\n",
    "同时，如果提示词比较复杂，你可以通过**分隔符**帮助模型理解你的意图。<br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b0d81507",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_B=\"\"\"\n",
    "<audience>初级Python开发者</audience>\n",
    "\n",
    "<task>函数性能优化，优化code中的代码。</task>\n",
    "\n",
    "<format>\n",
    "如有多种优化方案请按照如下格式进行输出：\n",
    "【优化方案X】\n",
    "问题描述：[描述]\n",
    "优化方案：[描述]\n",
    "示例代码：[代码块]\n",
    "</format>\n",
    "\n",
    "<code>\n",
    "def example(a):\n",
    "  b = []\n",
    "  for i in range(len(a)):\n",
    "    b.append(a[i]*2)\n",
    "  return sum(b)\n",
    "</code>\n",
    "\"\"\"\n",
    "\n",
    "reasoning_model_response(user_prompt=prompt_B)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c163ae4c",
   "metadata": {},
   "source": [
    "#### 技巧二：避免思维链提示<br>\n",
    "本节 4.5 中你了解到通过思维链（COT）技术让大模型深入思考提升回复效果。<br>\n",
    "一般来说，你无需提示推理模型“逐步思考”或“解释你的推理”，因为它们本身会进行深入的思考，你的提示可能反而限制推理模型的发挥。除非你需要大模型严格按照固定的思路去推理，这种情况很少发生。\n",
    "\n",
    "\n",
    "\n",
    "#### 技巧三：根据模型响应调整提示词<br>\n",
    "推理模型因其回复形式(包含**思考过程**)，天然适合你分析它的思考推理结论的过程，便于你调整提示词。<br>\n",
    "因此，你不需要纠结提示词是否足够完善，只需要不断与推理模型对话，过程中补充信息，完善提示词即可。<br>\n",
    "比如当你的描述**太抽象**或**无法准确描述**时，你可以用本节4.4讲到的**增加示例**的技巧来明确这些信息，这些示例有时可以从与模型的对话历史中挑选出来。<br>\n",
    "这个过程可以是重复多次的，不断尝试调整提示，让模型不断推理迭代，直到符合你的要求。<br>\n",
    "\n",
    "#### 技巧四：推理模型与通用模型分工协作完成复杂任务<br>\n",
    "推理模型通常像“更聪明的员工”，可以有效帮助你完成推理、规划等任务。但是推理或规划完成后的执行，如固定动作的快速处理，推理模型还是“过度思考”就显得有些多余了。<br>\n",
    "较好的做法是：让模型们分工协作，做它们各自擅长的工作，即推理模型进行“慢思考”完成规划或推理，通用模型进行“快思考”或调用工具完成指定动作。<br>\n",
    "你可以尝试运行并理解如下项目：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01807cca",
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "import os\n",
    "import json\n",
    "from typing import Generator\n",
    "\n",
    "class TaskPlanningSystem:\n",
    "    def __init__(self):\n",
    "        # 初始化客户端连接\n",
    "        self.client = OpenAI(\n",
    "            api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "            base_url=\"https://dashscope.aliyuncs.com/compatible-mode/v1\"\n",
    "        )\n",
    "        \n",
    "        # 系统工具集（可根据需要扩展）\n",
    "        self.tools = {\n",
    "            \"create_task\": {\n",
    "                \"desc\": \"创建新任务项\",\n",
    "                \"params\": {\"description\": \"str\", \"priority\": \"int\"}\n",
    "            },\n",
    "            \"schedule_event\": {\n",
    "                \"desc\": \"安排日程事件\", \n",
    "                \"params\": {\"title\": \"str\", \"time\": \"datetime\"}\n",
    "            }\n",
    "        }\n",
    "\n",
    "    def generate_plan(self, user_request: str) -> Generator[str, None, None]:\n",
    "        \"\"\"流式生成任务规划\"\"\"\n",
    "        # 构建规划提示词\n",
    "        system_prompt = f\"\"\"您是高级任务规划师，请将用户需求转化为可执行步骤：\n",
    "        \n",
    "        可用工具（格式：[[工具名称]]）：\n",
    "        {json.dumps(self.tools, indent=2)}\n",
    "        \n",
    "        输出要求：\n",
    "        1. 使用Markdown列表格式\n",
    "        2. 每个步骤标注工具名称\n",
    "        3. 包含必要参数示例\n",
    "        \"\"\"\n",
    "        model=\"qwq-32b\"\n",
    "        # 发起流式请求\n",
    "        completion = self.client.chat.completions.create(\n",
    "            model=model,\n",
    "            messages=[\n",
    "                {\"role\": \"system\", \"content\": system_prompt},\n",
    "                {\"role\": \"user\", \"content\": user_request}\n",
    "            ],\n",
    "            stream=True,\n",
    "            temperature=0.3\n",
    "        )\n",
    "\n",
    "        # 打印思考过程标题\n",
    "        print(f\"\\n\\n=== 【规划思考阶段】 使用推理模型：{model}===\")\n",
    "        is_answering = False\n",
    "        # 处理流式响应\n",
    "        for chunk in completion:\n",
    "            if chunk.choices:\n",
    "                delta = chunk.choices[0].delta\n",
    "                if hasattr(delta, 'reasoning_content') and delta.reasoning_content is not None:\n",
    "                    # 处理思考过程内容\n",
    "                    reasoning_content = delta.reasoning_content\n",
    "                    yield reasoning_content\n",
    "                else:\n",
    "                    # 切换到答案输出模式\n",
    "                    if delta.content != \"\" and not is_answering:\n",
    "                        print(f\"\\n\\n=== 【规划生成阶段】 使用推理模型：{model}===\")\n",
    "                        is_answering = True\n",
    "                    # 处理答案内容\n",
    "                    if delta.content:\n",
    "                        content = delta.content\n",
    "                        yield content\n",
    "\n",
    "    def execute_plan(self, plan: str) -> dict:\n",
    "        \"\"\"执行生成的任务计划\"\"\"\n",
    "        # 调用通用模型解析计划\n",
    "        analysis_prompt = f\"\"\"请解析以下任务计划并生成可执行指令：\n",
    "        \n",
    "        计划内容：\n",
    "        {plan}\n",
    "        \n",
    "        输出要求：\n",
    "        - 返回的content仅为JSON格式，不要包含其他信息，不要输出代码段。\n",
    "        - 包含工具名称和参数\n",
    "        - 示例：\n",
    "            {{\"steps\": [\n",
    "                {{\"tool\": \"create_task\", \"params\": {{\"description\": \"...\"}}}}\n",
    "            ]}}\n",
    "        \"\"\"\n",
    "        model=\"qwen-plus-0919\"\n",
    "        response = self.client.chat.completions.create(\n",
    "            model=model,\n",
    "            messages=[{\"role\": \"user\", \"content\": analysis_prompt}],\n",
    "            temperature=0\n",
    "        )\n",
    "\n",
    "        print(f\"\\n\\n使用通用模型{model}格式化输出：\\n{response.choices[0].message.content}\")\n",
    "        # 解析执行指令\n",
    "        try:\n",
    "            instructions = json.loads(response.choices[0].message.content)\n",
    "            return self._run_instructions(instructions)\n",
    "        except json.JSONDecodeError:\n",
    "            return {\"error\": \"指令解析失败\"}\n",
    "\n",
    "    def _run_instructions(self, instructions: dict) -> dict:\n",
    "        \"\"\"实际执行工具调用\"\"\"\n",
    "        results = []\n",
    "        for step in instructions.get(\"steps\", []):\n",
    "            tool = step.get(\"tool\")\n",
    "            params = step.get(\"params\", {})\n",
    "            \n",
    "            # 执行工具调用（此处为示例实现）\n",
    "            if tool == \"create_task\":\n",
    "                results.append({\n",
    "                    \"tool\": tool,\n",
    "                    \"result\": f\"已创建任务：{params.get('description')}\"\n",
    "                })\n",
    "            elif tool == \"schedule_event\":\n",
    "                results.append({\n",
    "                    \"tool\": tool,\n",
    "                    \"result\": f\"已安排日程：{params.get('title')}\"\n",
    "                })\n",
    "            else:\n",
    "                results.append({\"error\": f\"未知工具：{tool}\"})\n",
    "        \n",
    "        return {\"status\": \"completed\", \"results\": results}\n",
    "\n",
    "# 使用示例\n",
    "if __name__ == \"__main__\":\n",
    "    PlanningSystem = TaskPlanningSystem()\n",
    "    \n",
    "    # 示例用户请求\n",
    "    user_request = \"请安排下周的产品发布会并创建相关筹备任务\"\n",
    "    \n",
    "    # 规划生成阶段\n",
    "    plan_stream = PlanningSystem.generate_plan(user_request)\n",
    "    generated_plan = []\n",
    "    for chunk in plan_stream:\n",
    "        print(chunk, end=\"\", flush=True)\n",
    "        generated_plan.append(chunk)\n",
    "    \n",
    "    full_plan = \"\".join(generated_plan)\n",
    "    \n",
    "    print(\"\\n\\n=== 计划执行阶段 ===\")\n",
    "    result = PlanningSystem.execute_plan(full_plan)\n",
    "    print(f\"\\n调用工具执行，执行结果：\")\n",
    "    print(json.dumps(result, indent=2, ensure_ascii=False))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3cf7690c",
   "metadata": {},
   "source": [
    "如上代码实现了如下的核心交互流程，代码主要通过 qwq-32b 模型进行流式规划生成，再使用 qwen-plus-0919 进行指令解析，最后通过 _run_instructions 方法实现工具调用的解耦，便于后续扩展：\n",
    "\n",
    "<a href=\"https://img.alicdn.com/imgextra/i4/O1CN01uZWa8k243UBb3FDqO_!!6000000007335-0-tps-3604-1478.jpg\" target=\"_blank\">\n",
    "<img src=\"https://img.alicdn.com/imgextra/i4/O1CN01uZWa8k243UBb3FDqO_!!6000000007335-0-tps-3604-1478.jpg\" width=\"800\">\n",
    "</a>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30451423",
   "metadata": {},
   "source": [
    "## ✅ 本节小结\n",
    "\n",
    "通过学习本节课程，你分别掌握了适用于通用大模型和推理大模型的提示词技巧，灵活运用这些技巧可以有效保证AI回复质量的下限。<br>\n",
    "不过随着AI技术不断迭代，这些技巧也可能会不断改变（如推理模型可以不用再通过思维链提示提升效果），但你需要知道的是这些提示词技巧的核心目的在于：<br>\n",
    "<mark>讲清楚你的核心需求，提供丰富且有用的背景信息（上下文）</mark>——这对于你用好大模型至关重要。\n",
    "\n",
    "实际落地大模型应用的过程中，提示词部分经常让领域专家来共同设计。因此，在你的工程代码中硬编码提示词，应该考虑调整成可配置的，甚至应用流程也可配置，这样能更方便领域专家参与提示词和整个流程的设计。阿里云百炼提供了可视化的大模型[应用构建](https://help.aliyun.com/zh/model-studio/user-guide/application-introduction#7c79befb2djg9)能力，可以在页面上完成提示词编写、整个复杂应用的流程可视化搭建，非常适合在需要非技术背景的领域专家参与的大模型应用开发项目中。\n",
    "\n",
    "在下一节中，你将学习自动化评测方法测试答疑机器人的表现，你可以使用量化的指标来评测你的提示词的效果。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3166b70c",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "## 🔥 课后小测验\n",
    "\n",
    "### 🔍 单选题\n",
    "<details>\n",
    "<summary style=\"cursor: pointer; padding: 12px; border: 1px solid #dee2e6; border-radius: 6px;\">\n",
    "<b>以下哪个提示词要素用于明确要求大模型完成的任务❓</b>\n",
    "\n",
    "- A. 角色 (Role)     \n",
    "- B. 受众 (Audience)   \n",
    "- C. 任务目标 (Object)  \n",
    "- D. 上下文 (Context)  \n",
    "\n",
    "**【点击查看答案】**\n",
    "</summary>\n",
    "\n",
    "<div style=\"margin-top: 10px; padding: 15px;  border: 1px solid #dee2e6; border-radius: 0 0 6px 6px;\">\n",
    "\n",
    "✅ **参考答案：C**  \n",
    "📝 **解析**：\n",
    "- 任务目标 (Object) 明确规定了大模型需要执行的操作或达成的结果。其他选项并非直接定义任务本身。\n",
    "- 角色 (Role) 定义大模型扮演的身份，受众 (Audience) 定义目标群体，上下文 (Context) 提供背景信息。\n",
    "\n",
    "\n",
    "</div>\n",
    "</details>\n",
    "\n",
    "---\n",
    "\n",
    "\n",
    "### 🔍 多选题\n",
    "<details>\n",
    "<summary style=\"cursor: pointer; padding: 12px; border: 1px solid #dee2e6; border-radius: 6px;\">\n",
    "<b>假设你想使用大模型生成一段适合小学三年级学生阅读的关于太阳系的描述。以下哪个 user_query 的设计更合理❓</b>\n",
    "\n",
    "- A. user_query=\"Write about the solar system.\"    \n",
    "- B. user_query=\"Tell me about the solar system.\"     \n",
    "- C. user_query=\"Explain the solar system as if you were talking to a third-grade student.\"     \n",
    "- D. user_query=\"Write a short and engaging description of the solar system for a third-grade audience, focusing on key planets and their characteristics.\"   \n",
    "- E. user_query=\"太阳系是什么？\"   \n",
    "\n",
    "**【点击查看答案】**\n",
    "</summary>\n",
    "\n",
    "<div style=\"margin-top: 10px; padding: 15px; border: 1px solid #dee2e6; border-radius: 0 0 6px 6px;\">\n",
    "\n",
    "✅ **参考答案：CD**  \n",
    "📝 **解析**：\n",
    "- C、D 选项明确指定了目标读者，并对内容和风格提出了要求。\n",
    "\n",
    "</div>\n",
    "</details>\n",
    "\n",
    "\n",
    "---\n",
    "\n",
    "\n",
    "### 🔍 多选题\n",
    "<details>\n",
    "<summary style=\"cursor: pointer; padding: 12px; border: 1px solid #dee2e6; border-radius: 6px;\">\n",
    "<b>在使用推理型大模型（如qwq-32b）执行推理任务时。以下哪些提示词技巧是推荐的❓</b>\n",
    "\n",
    "- A. 给出简单、明确的任务指示    \n",
    "- B. 补充足够的背景信息     \n",
    "- C. 如有特定用户群体或特定任务要求，设定角色或受众     \n",
    "- D. 通过思维链提示帮助推理过程更为严谨可靠   \n",
    "- E. 当描述太抽象或无法准确描述时，可以通过增加示例来明确这些信息 \n",
    "\n",
    "**【点击查看答案】**\n",
    "</summary>\n",
    "\n",
    "<div style=\"margin-top: 10px; padding: 15px; border: 1px solid #dee2e6; border-radius: 0 0 6px 6px;\">\n",
    "\n",
    "✅ **参考答案：ABCE**  \n",
    "📝 **解析**：\n",
    "- 使用推理模型时应尽量避免使用思维链，这可能反而降低推理效果\n",
    "\n",
    "</div>\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b354883f",
   "metadata": {},
   "source": [
    "## ✉️ 评价反馈\n",
    "\n",
    "感谢你学习阿里云大模型ACP认证课程，如果你觉得课程有哪里写得好、哪里写得不好，期待你[通过问卷提交评价和反馈](https://survey.aliyun.com/apps/zhiliao/Mo5O9vuie)。\n",
    "\n",
    "你的批评和鼓励都是我们前进的动力。"
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": "learnacp",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
